#include "StdAfx.h"
#include "FileStream.h"

namespace System{
namespace IO{

VIRTUAL_GET_TYPE_IMPLEMENT(System::IO::FileStream, System_IO_FileStream)
VIRTUAL_TOSTRING_IMPLEMENT(System::IO::FileStream, System_IO_FileStream)

FileStream::FileStream(void)
{
	this->Init();
	m_File = NULL;
}

FileStream::FileStream(const TCHAR* pFileName, const TCHAR* mode)
{
	this->Init();

	#ifdef UNICODE
	errno_t error = _wfopen_s(&this->m_File, pFileName, mode);
	#else
	errno_t error = fopen_s(&this->m_File, pFileName, mode);
	#endif
}


FileStream::~FileStream(void)
{
	this->Close();
}

TCHAR FileStream::ReadChar()
{
	if(this->m_Cursor >= this->m_BufLen)
	{
		this->LoadBuffer();
	}

	if(this->m_Cursor < this->m_BufLen) {
		return this->m_Buffer[this->m_Cursor++];
	}

	return -1;
}

size_t FileStream::Read(void* buffer, size_t elementSize, size_t count)
{
	size_t retSize = 0;
	if(this->m_File != NULL) {
		if(this->m_BufLen > 0) {
			int len = count * elementSize;
			if(this->m_Cursor + len >= STREAM_BUF_SIZE) {
				int left = STREAM_BUF_SIZE - this->m_Cursor;
				if(left > 0) {
					memcpy(buffer, this->m_Buffer + this->m_Cursor, left);
					retSize = left;
				}

				int less = len - left;
				if(less > 0) {
					if(!feof(this->m_File)) {
						retSize += fread((char*)buffer + left, 1, less, this->m_File);
					}
					retSize = retSize / elementSize + retSize % elementSize;
				} else {
					retSize = count;
				}

				this->LoadBuffer();
			} else {
				memcpy(buffer, this->m_Buffer + this->m_Cursor, len);
				this->m_Cursor+= len;
				retSize = count;
			}
		} else {
			if(!feof(this->m_File)) {
				retSize = fread(buffer, elementSize, count, this->m_File);
				if(retSize == count) {
					this->LoadBuffer();
				}
			}
		}
	}

	return retSize;
}

System::MemString FileStream::ReadLine()
{
	System::MemString str;

	bool lineEnd = false;

	int start = this->m_Cursor;
	while(true){
		if(this->m_Cursor >= this->m_BufLen) {
			if(!this->LoadBuffer()) { break; }
		}

		for(; this->m_Cursor < this->m_BufLen; this->m_Cursor++){
			if(this->m_Buffer[this->m_Cursor] == '\r' || this->m_Buffer[this->m_Cursor] == '\n') {
				this->m_Cursor++;
				lineEnd = true;
				break;
			} else {
				//str += this->m_Buffer[this->m_Cursor];
			}
		}

		if(lineEnd) { break; }
	}

	/*TCHAR buf[1024] = {0};
	MultiByteToWideChar(CP_ACP, 0, this->m_Buffer, this->m_Cursor - start, buf, 1024);
	str = buf;*/

	
	return str;
}

void FileStream::SubString(char* buffer, size_t start, size_t end)
{
	if(start < this->m_BufLen && end < this->m_BufLen && start < end) {
		memcpy(buffer, this->m_Buffer + start, end - start);
	}


	/*for(int i = 0; start < end && start < this->m_BufLen; start++, i++) {
		buffer[i] = this->m_Buffer[start];
	}*/
}

long FileStream::GetPosition()
{
	if(this->m_File != NULL) {
		if(this->m_BufLen > 0) {
			return ftell(this->m_File) - this->m_BufLen + this->m_Cursor;
		} else {
			return ftell(this->m_File);
		}
	}

	return 0;
}

int FileStream::Skip(long offset, int origin)
{
	return fseek(this->m_File, offset, origin);
}


void FileStream::Init()
{
	this->m_BufLen = 0;
	this->m_Cursor = 0;
}

void FileStream::Close()
{
	if(this->m_File != NULL)
	{
		fclose(this->m_File);
		this->m_File = NULL;
	}
}

bool FileStream::LoadBuffer()
{
	if(feof(this->m_File)) {
		this->m_BufLen = 0;
	} else {
		this->m_BufLen = fread(this->m_Buffer, sizeof(char), STREAM_BUF_SIZE, this->m_File);
	}

	this->m_Cursor = 0;

	return this->m_BufLen > 0;
}




}
}